R packages I used during the workshop.
The dataset we will be using is the State Expenditures data set,
which you can load into your R session by passing the URL to
RSocrata::read.socrata().
This report provides information on expenditures (i.e., cash
transactions/payments) for the agencies that utilize the Statewide
Financial Management Application (SFMA) issued for the fiscal year 2024
(July 1, 2023 - June 30, 2024).
Viewing the data
We do not build an analysis around the data we have; we find the
data for the analysis that we need!
This chunk shows two ways we can load the data, one relies on an API
via RSocrata, whereas the second option relies on exporting the data
manually from Data.Oregon.Gov.
# Using RSocrata
state_expenditures <- read.socrata("https://data.oregon.gov/Revenue-Expense/Agency-Expenditures-Multi-Year-Report/y9g9-xsxs")
# Using csv file stored locally
#state_expenditures <- read.csv(here("data", "Agency_Expenditures_–_Multi-Year_Report_20250827.csv"), stringsAsFactors = FALSE)
glimpse(state_expenditures)
Rows: 567,728
Columns: 10
$ fiscal_year <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 20…
$ agency <int> 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 919, 9…
$ agency_1 <chr> "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTA…
$ budget_class <int> 3110, 3240, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 4100, 41…
$ budget_class_1 <chr> "CLASS/UNCLASS SALARY & PER DIEM", "UNEMPLOYMENT ASSESSMENT", "INSTATE TRAVEL", "INSTA…
$ expend_class <int> 3111, 3231, 4101, 4101, 4101, 4101, 4101, 4104, 4105, 4106, 4106, 4108, 4108, 4108, 41…
$ expend_class_1 <chr> "REGULAR EMPLOYEES", "UNEMPLOYMENT COMPENSATION & ASSESSMENT", "INSTATE MEALS WITH OVE…
$ vendor <chr> "DEPARTMENT OF ADMINISTRATIVE SERVICES", "EMPLOYMENT DEPARTMENT", "FRANK LEONARD JR", …
$ expense <dbl> 270.72, 5131.00, 59.00, 73.75, 88.50, 295.00, 458.13, 120.00, 414.01, 898.28, 2843.22,…
$ vendor_st <chr> "OR", "OR", "", "", "", "", "", "MO", "MO", "", "MO", "", "", "", "", "", "OR", "MO", …
Data quality checks
We’ll clean-up some of the types that should be treated as
characters. We’ll also rename variables for improved readability.
# basic clean-up
state_expenditures_clean <-
state_expenditures %>%
mutate(across(c(agency , expend_class, budget_class), ~as.character(.))) %>%
rename(
"agency_code" = agency,
"agency_name" = agency_1,
"budget_class_code" = budget_class,
"budget_class_name" = budget_class_1,
"expend_class_code" = expend_class,
"expend_class_name" = expend_class_1
)
glimpse(state_expenditures_clean)
Rows: 567,728
Columns: 10
$ fiscal_year <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023,…
$ agency_code <chr> "919", "919", "919", "919", "919", "919", "919", "919", "919", "919", "919", "919",…
$ agency_name <chr> "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL ESTATE AGY", "REAL E…
$ budget_class_code <chr> "3110", "3240", "4100", "4100", "4100", "4100", "4100", "4100", "4100", "4100", "41…
$ budget_class_name <chr> "CLASS/UNCLASS SALARY & PER DIEM", "UNEMPLOYMENT ASSESSMENT", "INSTATE TRAVEL", "IN…
$ expend_class_code <chr> "3111", "3231", "4101", "4101", "4101", "4101", "4101", "4104", "4105", "4106", "41…
$ expend_class_name <chr> "REGULAR EMPLOYEES", "UNEMPLOYMENT COMPENSATION & ASSESSMENT", "INSTATE MEALS WITH …
$ vendor <chr> "DEPARTMENT OF ADMINISTRATIVE SERVICES", "EMPLOYMENT DEPARTMENT", "FRANK LEONARD JR…
$ expense <dbl> 270.72, 5131.00, 59.00, 73.75, 88.50, 295.00, 458.13, 120.00, 414.01, 898.28, 2843.…
$ vendor_st <chr> "OR", "OR", "", "", "", "", "", "MO", "MO", "", "MO", "", "", "", "", "", "OR", "MO…
We can use inspectdf to view the unique counts, and most
common values for each of the categorical variables.
# unique counts by category
state_expenditures_clean %>%
inspect_cat()
Column (2/8): agency_name
Column (3/8): budget_class_code
Column (4/8): budget_class_name
Column (5/8): expend_class_code
Column (6/8): expend_class_name
Column (7/8): vendor
Column (8/8): vendor_st
We can see that there are discrepancies between the agency, budget,
and expenditure class codes since the total counts for these are
different. Let’s take a look at those.
# duplicates for agency codes
state_expenditures_clean %>%
distinct(agency_code, agency_name) %>%
count(agency_code, sort = TRUE) %>%
filter(n > 1)
# duplicates for budget class codes
state_expenditures_clean %>%
distinct(budget_class_code, budget_class_name) %>%
count(budget_class_code, sort = TRUE) %>%
filter(n > 1)
# duplicates for expenditure class codes
state_expenditures_clean %>%
distinct(expend_class_code, expend_class_name) %>%
count(expend_class_code, sort = TRUE) %>%
filter(n > 1)
What states are included for vendors?
# show all states included
state_expenditures_clean %>%
count(vendor_st, sort = TRUE)
Interestingly, this extends beyond US-based vendors with 67 rows
which includes blanks, ‘XX’, and several Canadian provinces.
At this point we may decide that the data quality issues require
engagement with the data owners of this asset to proceed with our
analysis.
Or we may be comfortable with proceeding!
Exploratory Analysis
Viewing total expenditures by year
state_expenditures_clean %>%
group_by(fiscal_year) %>%
reframe(total_expend_in_billions = sum(expense)/1e9)
state_expenditures_clean %>%
group_by(fiscal_year) %>%
reframe(total_expend_in_billions = sum(expense)/1e9) %>%
ggplot(aes(x = as.factor(fiscal_year), y = total_expend_in_billions)) +
geom_col() +
scale_y_continuous(labels = scales::label_currency()) +
theme_classic() +
labs(
y = "Total Expenditures ($ Billions)",
x = NULL,
caption = "\nData source:\n \'Agency Expenditures - Multi-Year Report\'\n As of December 17, 2024 from Data.Oregon.Gov"
)

How about viewing by agencies with the top 5 highest expenditures in
2024?
top_agencies <-
state_expenditures_clean %>%
filter(fiscal_year == 2024) %>%
group_by(agency_name) %>%
reframe(total_expenditures = sum(expense)) %>%
arrange(-total_expenditures) %>%
slice(1:5) %>%
pull(agency_name)
summary_by_top_agencies <-
state_expenditures_clean %>%
filter(agency_name %in% top_agencies) %>%
group_by(fiscal_year, agency_name) %>%
reframe(total_expend_in_billions = sum(expense)/1e9) %>%
mutate(
agency_name = fct_reorder(agency_name, total_expend_in_billions, .desc = TRUE)
)
summary_by_top_agencies %>%
ggplot(aes(x = as.factor(fiscal_year), y = total_expend_in_billions, group = agency_name)) +
geom_col() +
facet_wrap(~ agency_name, ncol = 3, scales = "free_y", axes = "margins") +
scale_y_continuous(labels = scales::label_currency()) +
theme_classic() +
labs(
y = "Total expenditures ($ Billions)",
x = NULL,
caption = "\nData source:\n \'Agency Expenditures - Multi-Year Report\'\n As of December 17, 2024 from Data.Oregon.Gov",
title = "Top 5 Agencies with the Highest Expenditures in 2024",
subtitle = "Axes for total expenditures varies by agency to show differences in scale."
)

8.27.2025
Amelia L. Vargas
LS0tDQp0aXRsZTogIlNPUkEgSW5jbHVzaXZlIEFuYWx5dGljcyBXb3Jrc2hvcCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClIgcGFja2FnZXMgSSB1c2VkIGR1cmluZyB0aGUgd29ya3Nob3AuIA0KDQpgYGB7ciBzZXR1cH0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KFJTb2NyYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShpbnNwZWN0ZGYpDQpsaWJyYXJ5KGZvcmNhdHMpDQpgYGANCg0KVGhlIGRhdGFzZXQgd2Ugd2lsbCBiZSB1c2luZyBpcyB0aGUgU3RhdGUgRXhwZW5kaXR1cmVzIGRhdGEgc2V0LCB3aGljaCB5b3UgY2FuIGxvYWQgaW50byB5b3VyIFIgc2Vzc2lvbiBieSBwYXNzaW5nIHRoZSBVUkwgdG8gYFJTb2NyYXRhOjpyZWFkLnNvY3JhdGEoKWAuIA0KDQpBYm91dCB0aGUgZGF0YTogDQo8aHR0cHM6Ly9kYXRhLm9yZWdvbi5nb3YvUmV2ZW51ZS1FeHBlbnNlL0FnZW5jeS1FeHBlbmRpdHVyZXMtTXVsdGktWWVhci1SZXBvcnQveTlnOS14c3hzL2Fib3V0X2RhdGE+DQoNClRoaXMgcmVwb3J0IHByb3ZpZGVzIGluZm9ybWF0aW9uIG9uIGV4cGVuZGl0dXJlcyAoaS5lLiwgY2FzaCB0cmFuc2FjdGlvbnMvcGF5bWVudHMpIGZvciANCnRoZSBhZ2VuY2llcyB0aGF0IHV0aWxpemUgdGhlIFN0YXRld2lkZSBGaW5hbmNpYWwgTWFuYWdlbWVudCBBcHBsaWNhdGlvbiAoU0ZNQSkgaXNzdWVkIA0KZm9yIHRoZSBmaXNjYWwgeWVhciAyMDI0IChKdWx5IDEsIDIwMjMgLSBKdW5lIDMwLCAyMDI0KS4gDQoNCiMgUHVycG9zZQ0KDQpCZWZvcmUgZGVmaW5pbmcgb3VyIHB1cnBvc2Ugd2Ugc2hvdWxkIGNvbnNpZGVyLi4uIA0KDQojIyBXaG8gbWlnaHQgYmUgaW50ZXJlc3RlZCBpbiBhbiBhbmFseXNpcyBvZiBleHBlbmRpdHVyZXM/IA0KDQoqIFB1YmxpYyBlbXBsb3llZXMgIA0KKiBBZ2VuY2llcy9hZ2VuY3kgaGVhZHMgIA0KKiBQdWJsaWMvdGF4cGF5ZXJzICANCiogTGVnaXNsYXRvcnMgIA0KKiBWZW5kb3JzL1N1cHBsaWVycyAgDQoqIEF1ZGl0b3JzICANCiogQW5hbHlzdHMNCg0KDQojIyBXaGF0IGFyZSB0aGUgYmVuZWZpdHM/DQoNCiogUHJvY2VzcyBpbXByb3ZlbWVudHMgKGludGVybmFsIGFuZCBleHRlcm5hbCkgIA0KKiBWaWV3aW5nIG91dGxpZXJzIChpZGVudGlmeWluZyB0b28gc21hbGwgb3IgdG9vIGxhcmdlIG9mIGV4cGVuZGl0dXJlcykgDQoqIFRyZW5kcywgZS5nLiBzZWVpbmcgdGhlIGdlbmVyYWwgcGF0dGVybiAtIHdoYXQgYXJlIHRoZSBoaWdoZXN0L2xvd2VzdCBleHBlbmRpdHVyZXMsIHdoYXQgYXJlIHRoZSBtb3N0IGNvbW1vbiBleHBlbmRpdHVyZXMsIGV0Yy4NCiogQ29tcGxpYW5jZSwgdG8gZW5zdXJlIHRoYXQgd2UgYXJlIGZvbGxvd2luZyBvdXIgcHJvY3VyZW1lbnQgcnVsZXMNCiogT3Bwb3J0dW5pdGllcyBmb3IgY29uc29saWRhdGluZywgZ2V0dGluZyBiZXR0ZXIgY29udHJhY3RzDQoqIEJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHdoZXJlIHRheGVzIGdvDQoNCiMjIFdoYXQgYXJlIHRoZSByaXNrcz8gDQoNCiogTGVnaXNsYXRvcnMgbWF5IHNlZSB0aGUgYW5hbHlzaXMgYW5kIHRoaW5rIHRoYXQgY29zdHMgYXJlIHRvbyBoaWdoIGFuZCB1c2UgaXQgYXMgcmF0aW9uYWxlIHRvIGN1dCBidWRnZXRzICANCiogUGF0dGVybnMgbWF5IGJlIHJldmVhbGVkIHRoYXQgaGFybSByZXB1dGF0aW9ucyAoaW5zdGl0dXRpb25hbCwgaW5kaXZpZHVhbCwgZXRjKQ0KDQpQdXJwb3NlOiANCk1ha2UgdGhlIGV4cGVuZGl0dXJlcyBkYXRhIHNldCBtb3JlIGFjY2Vzc2libGUgdG8gdGhvc2UgaW50ZXJlc3RlZCBpbiB0aGUgYW5hbHlzaXMgYnkgcHJvdmlkaW5nDQoNCkV4cGVuc2UgdHJlbmRzICANCg0KKiBPdmVyYWxsIGV4cGVuZGl0dXJlcyBieSB5ZWFyICANCiogRXhwZW5zZSBieSB5ZWFyIGJ5IGFnZW5jeSAgDQoqIEV4cGVuc2UgYnkgY2F0ZWdvcnkgYnkgYWdlbmN5ICANCiogRXhwZW5zZSBieSBjYXRlZ29yeSBieSB2ZW5kb3IgIA0KDQpEZWVwIGRpdmUgaW50byBvdXRsaWVycyAgDQoNCiogSGlnaCAmIExvdyBleHBlbmRpdHVyZXMgIA0KKiBleHBlbmRpdHVyZXMgb3V0IG9mIGNvbXBsaWFuY2Ugd2l0aCBwcm9jdXJlbWVudCBzdGF0dWVzL3J1bGVzL2d1aWRhbmNlDQoNCiMgVmlld2luZyB0aGUgZGF0YSAgDQoNCipXZSBkbyBub3QgYnVpbGQgYW4gYW5hbHlzaXMgYXJvdW5kIHRoZSBkYXRhIHdlIGhhdmU7IHdlIGZpbmQgdGhlIGRhdGEgZm9yIHRoZSBhbmFseXNpcyB0aGF0IHdlIG5lZWQhKg0KDQpUaGlzIGNodW5rIHNob3dzIHR3byB3YXlzIHdlIGNhbiBsb2FkIHRoZSBkYXRhLCBvbmUgcmVsaWVzIG9uIGFuIEFQSSB2aWEgUlNvY3JhdGEsIHdoZXJlYXMgdGhlIHNlY29uZCBvcHRpb24gcmVsaWVzIG9uIGV4cG9ydGluZyB0aGUgZGF0YSBtYW51YWxseSBmcm9tIA0KRGF0YS5PcmVnb24uR292Lg0KDQpgYGB7ciBsb2FkLWV4cGVuZGl0dXJlLWRhdGEsIGVjaG89VFJVRX0NCiMgVXNpbmcgUlNvY3JhdGENCnN0YXRlX2V4cGVuZGl0dXJlcyA8LSByZWFkLnNvY3JhdGEoImh0dHBzOi8vZGF0YS5vcmVnb24uZ292L1JldmVudWUtRXhwZW5zZS9BZ2VuY3ktRXhwZW5kaXR1cmVzLU11bHRpLVllYXItUmVwb3J0L3k5ZzkteHN4cyIpDQoNCiMgVXNpbmcgY3N2IGZpbGUgc3RvcmVkIGxvY2FsbHkNCiNzdGF0ZV9leHBlbmRpdHVyZXMgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YSIsICJBZ2VuY3lfRXhwZW5kaXR1cmVzX+KAk19NdWx0aS1ZZWFyX1JlcG9ydF8yMDI1MDgyNy5jc3YiKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQpnbGltcHNlKHN0YXRlX2V4cGVuZGl0dXJlcykNCmBgYA0KIyMgRGF0YSBxdWFsaXR5IGNoZWNrcw0KDQpXZSdsbCBjbGVhbi11cCBzb21lIG9mIHRoZSB0eXBlcyB0aGF0IHNob3VsZCBiZSB0cmVhdGVkIGFzIGNoYXJhY3RlcnMuIFdlJ2xsIGFsc28gcmVuYW1lIHZhcmlhYmxlcyBmb3IgaW1wcm92ZWQgcmVhZGFiaWxpdHkuDQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgYmFzaWMgY2xlYW4tdXANCnN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiA8LSANCiAgc3RhdGVfZXhwZW5kaXR1cmVzICU+JSANCiAgbXV0YXRlKGFjcm9zcyhjKGFnZW5jeSAsIGV4cGVuZF9jbGFzcywgYnVkZ2V0X2NsYXNzKSwgfmFzLmNoYXJhY3RlciguKSkpICU+JSANCiAgcmVuYW1lKA0KICAgICJhZ2VuY3lfY29kZSIgPSBhZ2VuY3ksDQogICAgImFnZW5jeV9uYW1lIiA9IGFnZW5jeV8xLA0KICAgICJidWRnZXRfY2xhc3NfY29kZSIgPSBidWRnZXRfY2xhc3MsDQogICAgImJ1ZGdldF9jbGFzc19uYW1lIiA9IGJ1ZGdldF9jbGFzc18xLA0KICAgICJleHBlbmRfY2xhc3NfY29kZSIgPSBleHBlbmRfY2xhc3MsDQogICAgImV4cGVuZF9jbGFzc19uYW1lIiA9IGV4cGVuZF9jbGFzc18xDQogICkNCg0KZ2xpbXBzZShzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4pDQpgYGANCldlIGNhbiB1c2UgYGluc3BlY3RkZmAgdG8gdmlldyB0aGUgdW5pcXVlIGNvdW50cywgYW5kIG1vc3QgY29tbW9uIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiANCg0KYGBge3IgZWNobz1UUlVFfQ0KIyB1bmlxdWUgY291bnRzIGJ5IGNhdGVnb3J5DQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBpbnNwZWN0X2NhdCgpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBkaXNjcmVwYW5jaWVzIGJldHdlZW4gdGhlIGFnZW5jeSwgYnVkZ2V0LCBhbmQgZXhwZW5kaXR1cmUgY2xhc3MgY29kZXMgc2luY2UgdGhlIHRvdGFsIGNvdW50cyBmb3IgdGhlc2UgYXJlIGRpZmZlcmVudC4gDQpMZXQncyB0YWtlIGEgbG9vayBhdCB0aG9zZS4gDQoNCmBgYHtyIGlkZW50aWZ5LWR1cGxpY2F0ZXMsIGVjaG89VFJVRX0NCiMgZHVwbGljYXRlcyBmb3IgYWdlbmN5IGNvZGVzDQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBkaXN0aW5jdChhZ2VuY3lfY29kZSwgYWdlbmN5X25hbWUpICU+JSANCiAgY291bnQoYWdlbmN5X2NvZGUsIHNvcnQgPSBUUlVFKSAlPiUgDQogIGZpbHRlcihuID4gMSkNCg0KIyBkdXBsaWNhdGVzIGZvciBidWRnZXQgY2xhc3MgY29kZXMNCnN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGRpc3RpbmN0KGJ1ZGdldF9jbGFzc19jb2RlLCBidWRnZXRfY2xhc3NfbmFtZSkgJT4lIA0KICBjb3VudChidWRnZXRfY2xhc3NfY29kZSwgc29ydCA9IFRSVUUpICU+JSANCiAgZmlsdGVyKG4gPiAxKQ0KDQojIGR1cGxpY2F0ZXMgZm9yIGV4cGVuZGl0dXJlIGNsYXNzIGNvZGVzDQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBkaXN0aW5jdChleHBlbmRfY2xhc3NfY29kZSwgZXhwZW5kX2NsYXNzX25hbWUpICU+JSANCiAgY291bnQoZXhwZW5kX2NsYXNzX2NvZGUsIHNvcnQgPSBUUlVFKSAlPiUgDQogIGZpbHRlcihuID4gMSkNCmBgYA0KDQpXaGF0IHN0YXRlcyBhcmUgaW5jbHVkZWQgZm9yIHZlbmRvcnM/DQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgc2hvdyBhbGwgc3RhdGVzIGluY2x1ZGVkDQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBjb3VudCh2ZW5kb3Jfc3QsIHNvcnQgPSBUUlVFKQ0KYGBgDQpJbnRlcmVzdGluZ2x5LCB0aGlzIGV4dGVuZHMgYmV5b25kIFVTLWJhc2VkIHZlbmRvcnMgd2l0aCA2NyByb3dzIHdoaWNoIGluY2x1ZGVzIGJsYW5rcywgJ1hYJywgYW5kIHNldmVyYWwgQ2FuYWRpYW4gcHJvdmluY2VzLg0KDQpBdCB0aGlzIHBvaW50IHdlIG1heSBkZWNpZGUgdGhhdCB0aGUgZGF0YSBxdWFsaXR5IGlzc3VlcyByZXF1aXJlIGVuZ2FnZW1lbnQgd2l0aCB0aGUgZGF0YSBvd25lcnMgb2YgdGhpcyBhc3NldCB0byBwcm9jZWVkIHdpdGggb3VyIGFuYWx5c2lzLiANCg0KT3Igd2UgbWF5IGJlIGNvbWZvcnRhYmxlIHdpdGggcHJvY2VlZGluZyENCg0KIyBFeHBsb3JhdG9yeSBBbmFseXNpcw0KDQpWaWV3aW5nIHRvdGFsIGV4cGVuZGl0dXJlcyBieSB5ZWFyDQoNCmBgYHtyIGVjaG89VFJVRX0NCnN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGdyb3VwX2J5KGZpc2NhbF95ZWFyKSAlPiUgDQogIHJlZnJhbWUodG90YWxfZXhwZW5kX2luX2JpbGxpb25zID0gc3VtKGV4cGVuc2UpLzFlOSkNCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdGF0ZV9leHBlbmRpdHVyZXNfY2xlYW4gJT4lIA0KICBncm91cF9ieShmaXNjYWxfeWVhcikgJT4lIA0KICByZWZyYW1lKHRvdGFsX2V4cGVuZF9pbl9iaWxsaW9ucyA9IHN1bShleHBlbnNlKS8xZTkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYXMuZmFjdG9yKGZpc2NhbF95ZWFyKSwgeSA9IHRvdGFsX2V4cGVuZF9pbl9iaWxsaW9ucykpICsgDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9jdXJyZW5jeSgpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArIA0KICBsYWJzKA0KICAgIHkgPSAiVG90YWwgRXhwZW5kaXR1cmVzICgkIEJpbGxpb25zKSIsIA0KICAgIHggPSBOVUxMLA0KICAgIGNhcHRpb24gPSAiXG5EYXRhIHNvdXJjZTpcbiBcJ0FnZW5jeSBFeHBlbmRpdHVyZXMgLSBNdWx0aS1ZZWFyIFJlcG9ydFwnXG4gQXMgb2YgRGVjZW1iZXIgMTcsIDIwMjQgZnJvbSBEYXRhLk9yZWdvbi5Hb3YiDQogICkNCmBgYA0KDQoNCkhvdyBhYm91dCB2aWV3aW5nIGJ5IGFnZW5jaWVzIHdpdGggdGhlIHRvcCA1IGhpZ2hlc3QgZXhwZW5kaXR1cmVzIGluIDIwMjQ/IA0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0b3BfYWdlbmNpZXMgPC0gDQogIHN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGZpbHRlcihmaXNjYWxfeWVhciA9PSAyMDI0KSAlPiUgDQogIGdyb3VwX2J5KGFnZW5jeV9uYW1lKSAlPiUgDQogIHJlZnJhbWUodG90YWxfZXhwZW5kaXR1cmVzID0gc3VtKGV4cGVuc2UpKSAlPiUgDQogIGFycmFuZ2UoLXRvdGFsX2V4cGVuZGl0dXJlcykgJT4lIA0KICBzbGljZSgxOjUpICU+JSANCiAgcHVsbChhZ2VuY3lfbmFtZSkNCg0Kc3VtbWFyeV9ieV90b3BfYWdlbmNpZXMgPC0gDQogIHN0YXRlX2V4cGVuZGl0dXJlc19jbGVhbiAlPiUgDQogIGZpbHRlcihhZ2VuY3lfbmFtZSAlaW4lIHRvcF9hZ2VuY2llcykgJT4lIA0KICBncm91cF9ieShmaXNjYWxfeWVhciwgYWdlbmN5X25hbWUpICU+JSANCiAgcmVmcmFtZSh0b3RhbF9leHBlbmRfaW5fYmlsbGlvbnMgPSBzdW0oZXhwZW5zZSkvMWU5KSAlPiUgDQogIG11dGF0ZSgNCiAgICBhZ2VuY3lfbmFtZSA9IGZjdF9yZW9yZGVyKGFnZW5jeV9uYW1lLCB0b3RhbF9leHBlbmRfaW5fYmlsbGlvbnMsIC5kZXNjID0gVFJVRSkNCiAgKQ0KICANCnN1bW1hcnlfYnlfdG9wX2FnZW5jaWVzICAlPiUgDQogIGdncGxvdChhZXMoeCA9IGFzLmZhY3RvcihmaXNjYWxfeWVhciksIHkgPSB0b3RhbF9leHBlbmRfaW5fYmlsbGlvbnMsIGdyb3VwID0gYWdlbmN5X25hbWUpKSArIA0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+IGFnZW5jeV9uYW1lLCBuY29sID0gMywgc2NhbGVzID0gImZyZWVfeSIsIGF4ZXMgPSAibWFyZ2lucyIpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX2N1cnJlbmN5KCkpICsNCiAgdGhlbWVfY2xhc3NpYygpICsgDQogIGxhYnMoDQogICAgeSA9ICJUb3RhbCBleHBlbmRpdHVyZXMgKCQgQmlsbGlvbnMpIiwgDQogICAgeCA9IE5VTEwsDQogICAgY2FwdGlvbiA9ICJcbkRhdGEgc291cmNlOlxuIFwnQWdlbmN5IEV4cGVuZGl0dXJlcyAtIE11bHRpLVllYXIgUmVwb3J0XCdcbiBBcyBvZiBEZWNlbWJlciAxNywgMjAyNCBmcm9tIERhdGEuT3JlZ29uLkdvdiIsDQogICAgdGl0bGUgPSAiVG9wIDUgQWdlbmNpZXMgd2l0aCB0aGUgSGlnaGVzdCBFeHBlbmRpdHVyZXMgaW4gMjAyNCIsDQogICAgc3VidGl0bGUgPSAiQXhlcyBmb3IgdG90YWwgZXhwZW5kaXR1cmVzIHZhcmllcyBieSBhZ2VuY3kgdG8gc2hvdyBkaWZmZXJlbmNlcyBpbiBzY2FsZS4iDQogICkNCmBgYA0KDQo4LjI3LjIwMjUgIA0KQW1lbGlhIEwuIFZhcmdhcw==